아파치 카프카
1. 서론
1.1 아파치 카프카의 정의와 비전
현대 데이터 아키텍처의 패러다임은 ’저장된 데이터(Data at Rest)’에서 ’움직이는 데이터(Data in Motion)’로 빠르게 전환되고 있다. 이러한 변화의 중심에는 아파치 카프카(Apache Kafka®)가 있다. 카프카는 단순히 메시지를 전달하는 전통적인 메시지 큐(Message Queue)가 아니라, 실시간으로 발생하는 대규모 데이터 스트림을 수집, 저장, 처리하기 위해 설계된 **분산 이벤트 스트리밍 플랫폼(Distributed Event Streaming Platform)**이다.1 이는 기업의 모든 활동, 즉 결제, 재고 변동, 사용자 클릭, 센서 데이터 등 ’무언가 일어났다’는 사실을 나타내는 ’이벤트(Event)’의 흐름을 실시간으로 포착하고, 이를 조직의 중앙 신경망처럼 활용할 수 있게 하는 기술적 비전을 제시한다.1 카프카는 메시징, 스토리지, 스트림 처리라는 세 가지 핵심 기능을 하나의 통합된 솔루션으로 제공함으로써, 데이터가 생성되는 순간부터 분석 및 활용에 이르기까지의 전 과정을 매끄럽게 연결한다.2
1.2 안내서의 목적과 구성
본 안내서는 아파치 카프카의 핵심 철학부터 내부 아키텍처, 고성능의 원리, 실제 활용법, 그리고 광범위한 데이터 생태계 내에서의 전략적 위치까지 다각적이고 심층적으로 분석하는 것을 목표로 한다. 이를 통해 독자는 카프카의 기술적 본질을 이론적으로 완벽히 이해하고, 나아가 복잡한 실무 환경에서 카프카를 자신감 있게 설계하고 적용할 수 있는 역량을 갖추게 될 것이다. 안내서는 다음과 같이 구성된다.
- 제 1장에서는 이벤트 스트리밍 패러다임과 카프카의 근간을 이루는 분산 커밋 로그 개념을 시작으로 프로듀서, 컨슈머, 브로커, 토픽, 파티션 등 핵심 구성 요소의 역할과 상호작용을 심층적으로 분석한다. 특히, KRaft 프로토콜 도입을 통한 아키텍처의 진화를 중점적으로 다룬다.
- 제 2장에서는 카프카가 어떻게 압도적인 처리량과 확장성을 달성하는지 그 원리를 파헤친다. Zero-Copy, 순차 I/O와 같은 기술적 최적화와 파티셔닝 전략이 시스템 성능에 미치는 영향을 분석한다.
- 제 3장에서는 로컬 환경 구축부터 CLI를 이용한 기본 조작, 그리고 Java와 Python을 사용한 클라이언트 프로그래밍까지 실질적인 활용 방법을 단계별 가이드와 코드 예제를 통해 제시한다.
- 제 4장에서는 로그 수집, 이벤트 소싱부터 이벤트 기반 마이크로서비스 아키텍처 구축에 이르기까지 카프카의 주요 사용 사례를 살펴보고, Netflix, Uber와 같은 글로벌 기업들의 성공적인 적용 전략을 분석한다.
- 제 5장에서는 전통적인 메시지 브로커인 RabbitMQ, 그리고 Google Pub/Sub, Amazon Kinesis와 같은 클라우드 관리형 서비스와의 비교 분석을 통해 각 기술의 장단점과 적합한 사용 시나리오를 명확히 제시한다.
이러한 체계적인 접근을 통해 본 안내서는 아파치 카프카에 대한 단편적인 지식을 넘어, 현대 데이터 중심 애플리케이션을 구축하고자 하는 모든 개발자와 아키텍트를 위한 포괄적이고 깊이 있는 기술 지침서가 되고자 한다.
2. 아파치 카프카의 핵심 철학과 아키텍처
아파치 카프카의 강력함은 단순한 기능의 집합이 아닌, 일관된 철학과 그를 뒷받침하는 견고한 아키텍처에서 비롯된다. 본 장에서는 카프카를 움직이는 근본 원리인 이벤트 스트리밍 패러다임과 분산 커밋 로그의 개념을 탐구하고, 이를 구현하는 핵심 구성 요소들의 역할과 상호작용을 심층적으로 분석한다.
2.1 이벤트 스트리밍 패러다임의 이해
이벤트 스트리밍의 핵심은 ’이벤트(Event)’이다. 카프카에서 이벤트란 “세상이나 비즈니스에서 ’무언가 일어났다’는 사실의 기록“으로 정의된다.1 이는 단순히 ’메시지’나 ’레코드’라고도 불리며, 개념적으로 키(Key), 값(Value), 타임스탬프(Timestamp), 그리고 선택적인 메타데이터 헤더(Header)로 구성된다.1 예를 들어, ‘사용자 A가 상품 B를 구매했다’, ‘IoT 센서 X에서 온도 25도를 측정했다’, ’서버 Z에서 오류가 발생했다’와 같은 모든 개별적인 사건이 하나의 이벤트가 될 수 있다.1
이벤트 스트림(Event Stream)은 이러한 이벤트들의 연속적인 흐름을 의미한다. 이는 시간의 흐름에 따라 비즈니스의 모든 활동을 순서대로 기록하는 것과 같다.2 카프카는 바로 이 이벤트 스트림을 안정적으로 포착하고, 영구적으로 저장하며, 실시간으로 또는 과거의 데이터를 필요에 따라 처리할 수 있도록 지원하는 플랫폼이다.3 이 패러다임은 데이터를 정적인 상태로 데이터베이스에 저장하고 배치(batch) 작업으로 처리하던 전통적인 방식에서 벗어나, 데이터가 발생하는 즉시 반응하고 가치를 창출하는 ‘움직이는 데이터’ 중심의 아키텍처를 가능하게 한다.
2.2 분산 커밋 로그(Distributed Commit Log): 카프카의 심장부
카프카의 모든 기능과 성능은 ’파티션된 분산 커밋 로그(Partitioned Distributed Commit Log)’라는 단순하지만 지극히 강력한 데이터 구조에서 비롯된다.2 커밋 로그는 데이터가 추가만 가능한(append-only), 순서가 보장되는(ordered), 그리고 한 번 기록되면 변경할 수 없는(immutable) 레코드의 시퀀스다.5
이 구조가 중요한 이유는 다음과 같다.
- 성능: 데이터는 항상 로그의 끝에 순차적으로 추가된다. 이는 디스크의 임의 위치에 접근하는 랜덤 I/O(Random I/O)보다 훨씬 빠른 순차 I/O(Sequential I/O)를 가능하게 하여 쓰기 성능을 극대화한다.7
- 단순성과 안정성: 데이터가 불변(immutable)이기 때문에 복잡한 동시성 제어나 데이터 수정 로직이 필요 없다. 이는 시스템 설계를 단순화하고, 데이터 복제, 장애 복구, 일관성 유지 메커니즘을 매우 안정적이고 예측 가능하게 만든다.7
- 데이터 재처리(Replay): 로그에 기록된 이벤트는 삭제되지 않고 보존 기간 동안 유지된다. 따라서 여러 컨슈머들이 각자의 필요에 따라 동일한 이벤트 스트림을 처음부터 다시 읽거나 특정 시점부터 읽는 것이 가능하다. 이는 장애 복구, A/B 테스팅, 새로운 분석 애플리케이션 도입 등을 매우 용이하게 한다.2
결론적으로 카프카는 이 분산 커밋 로그를 통해 메시징 시스템의 역할과 데이터베이스의 영속성을 동시에 제공하는 독특한 위치를 점하게 된다.
2.3 주요 구성 요소 심층 분석
카프카의 아키텍처는 명확하게 정의된 몇 가지 핵심 구성 요소들의 상호작용으로 이루어진다.
-
프로듀서 (Producer): 프로듀서는 이벤트를 생성하여 카프카 클러스터 내의 특정 토픽으로 발행(publish)하는 클라이언트 애플리케이션이다.8 프로듀서는 단순히 데이터를 던지는 역할만 하는 것이 아니라, 어떤 레코드를 어느 파티션에 할당할지 결정하는 중요한 역할을 수행한다. 이는 파티셔닝 전략(Partitioning Strategy)을 통해 이루어지며, 메시지 키를 기반으로 하거나 라운드 로빈 방식으로 분배하는 등의 방법을 사용한다.9 프로듀서는 컨슈머의 존재나 상태에 대해 전혀 알지 못하며, 브로커로부터 메시지가 성공적으로 저장되었다는 확인(acknowledgment)만 받으면 자신의 임무를 완수한다. 이러한 완전한 분리는 시스템의 확장성을 보장하는 핵심 설계 원칙이다.1
-
컨슈머 (Consumer): 컨슈머는 특정 토픽들을 구독(subscribe)하여 이벤트를 읽고 처리하는 클라이언트 애플리케이션이다.8 카프카 컨슈머의 가장 큰 특징은 ‘풀(pull)’ 모델을 사용한다는 점이다.7 즉, 브로커가 컨슈머에게 데이터를 밀어주는(push) 것이 아니라, 컨슈머가 자신의 처리 능력과 속도에 맞춰 능동적으로 브로커로부터 데이터를 가져온다. 이는 컨슈머가 데이터 폭주로 인해 압도당하는 것을 방지하고, 각기 다른 성능을 가진 다양한 컨슈머들이 독립적으로 동작할 수 있게 한다.7
-
브로커 (Broker): 브로커는 카프카 클러스터를 구성하는 개별 서버 인스턴스다.3 각 브로커는 하나 이상의 토픽 파티션에 대한 데이터를 디스크에 저장하고, 프로듀서의 쓰기 요청과 컨슈머의 읽기 요청을 처리하는 실질적인 작업을 수행한다.8 카프카 클러스터는 여러 브로커로 구성되며, 이를 통해 데이터의 분산 저장과 부하 분산을 달성한다. 단일 브로커 인스턴스만으로도 초당 수십만 건의 읽기/쓰기 요청을 처리할 수 있는 높은 성능을 지니고 있다.8
-
토픽 (Topic): 토픽은 이벤트가 발행되고 저장되는 논리적인 채널 또는 카테고리다. 파일시스템의 폴더와 유사하게, 관련된 이벤트들을 그룹화하는 데 사용된다.1 예를 들어, ‘orders’, ‘payments’, ’user-clicks’와 같은 토픽을 만들어 각각의 비즈니스 이벤트를 분리하여 관리할 수 있다.6 프로듀서는 특정 토픽에 메시지를 쓰고, 컨슈머는 특정 토픽을 구독하여 메시지를 읽는다.
-
파티션 (Partition): 파티션은 토픽을 물리적으로 분할한 단위이자, 카프카 확장성의 핵심이다.9 하나의 토픽은 하나 이상의 파티션으로 구성되며, 이 파티션들은 클러스터 내의 여러 브로커에 분산되어 저장될 수 있다.5 토픽의 데이터를 여러 파티션으로 나누는 것은 하나의 거대한 로그 파일을 여러 개의 작은 로그 파일로 쪼개는 것과 같다. 이를 통해 단일 머신의 저장 용량이나 처리 능력의 한계를 넘어설 수 있다.11 또한, 파티션은 병렬 처리의 기본 단위(unit of parallelism)로 작동한다. 파티션 수가 많을수록 더 많은 컨슈머가 동시에 작업에 참여하여 전체 처리량을 높일 수 있다.5 단, 하나의 파티션 내에서는 메시지의 순서가 엄격하게 보장되지만, 토픽 전체에 걸친 메시지의 전역적인 순서는 보장되지 않는다.11
-
오프셋 (Offset): 오프셋은 각 파티션 내에서 모든 이벤트가 할당받는 고유하고 순차적인 식별 번호(일종의 인덱스)다.5 컨슈머는 이 오프셋을 통해 자신이 특정 파티션의 데이터를 어디까지 읽었는지를 추적한다. 중요한 점은 이 오프셋 정보가 브로커가 아닌 컨슈머 측에서 관리되고, 주기적으로 카프카 내의 특정 토픽(
__consumer_offsets)에 커밋(commit)된다는 것이다.7 이 설계 덕분에 카프카 브로커는 각 컨슈머의 읽기 상태를 추적할 필요가 없는 ‘상태 비저장(stateless)’ 서버로 남을 수 있으며, 이는 브로커의 부하를 줄이고 시스템을 단순하게 유지하는 데 크게 기여한다.
2.4 클러스터링과 내결함성: 리더, 팔로워, 그리고 복제 메커니즘
카프카는 분산 시스템으로서 개별 브로커의 장애에 견딜 수 있는 내결함성(Fault Tolerance)을 갖추고 있다. 이는 파티션의 복제(Replication) 메커니즘을 통해 달성된다.3
각 파티션은 복제 계수(Replication Factor) 설정에 따라 여러 개의 복제본(Replica)을 갖는다. 이 복제본들은 클러스터 내의 서로 다른 브로커에 분산되어 저장된다. 복제본들은 두 가지 역할을 수행한다 7:
- 리더 (Leader) 복제본: 각 파티션은 오직 하나의 리더 복제본을 가진다. 해당 파티션에 대한 모든 프로듀서의 쓰기 요청과 컨슈머의 읽기 요청은 전적으로 이 리더를 통해서만 처리된다.7
- 팔로워 (Follower) 복제본: 리더를 제외한 나머지 복제본들은 팔로워 역할을 한다. 팔로워들은 클라이언트의 요청을 직접 처리하지 않고, 대신 리더로부터 데이터를 지속적으로 가져와(fetch) 자신의 로그를 리더와 동일한 상태로 유지하는 데에만 집중한다.7 즉, 리더의 데이터를 수동적으로 복제하는 백업 역할을 수행한다.
만약 특정 파티션의 리더가 위치한 브로커에 장애가 발생하면, 카프카 컨트롤러는 해당 파티션의 팔로워들 중에서 하나를 새로운 리더로 선출한다.7 이 과정을 ’리더 선출(Leader Election)’이라고 하며, 이를 통해 서비스 중단을 최소화하고 데이터 유실 없이 운영을 지속할 수 있다. 이처럼 리더-팔로워 모델은 카프카의 고가용성과 데이터 내구성을 보장하는 핵심적인 메커니즘이다.
2.5 컨슈머 그룹과 리밸런싱
카프카는 큐잉(Queuing) 모델과 발행-구독(Publish-Subscribe) 모델의 장점을 결합하기 위해 ’컨슈머 그룹(Consumer Group)’이라는 독창적인 개념을 도입했다.2
- 컨슈머 그룹 (Consumer Group): 하나 이상의 컨슈머 인스턴스가 논리적으로 하나의 그룹을 형성하여 특정 토픽의 메시지를 함께 소비하는 메커니즘이다.9 주로 동일한 애플리케이션의 여러 인스턴스들이 하나의 컨슈머 그룹을 구성하여 작업을 병렬로 처리하고 부하를 분산시킨다.9
컨슈머 그룹의 핵심 규칙은 **“그룹 내에서 하나의 파티션은 오직 하나의 컨슈머 인스턴스에 의해서만 소비된다”**는 것이다.9 예를 들어, 6개의 파티션을 가진 토픽을 3개의 컨슈머 인스턴스로 구성된 그룹이 구독한다면, 카프카는 각 컨슈머에게 2개의 파티션을 할당하여 작업을 분배한다. 만약 컨슈머 인스턴스를 6개로 늘리면 각 컨슈머는 하나의 파티션을 담당하게 되어 병렬성을 극대화할 수 있다. 이 덕분에 컨슈머 애플리케이션의 수평적 확장(horizontal scaling)이 매우 용이해진다.9
- 리밸런싱 (Rebalancing): 컨슈머 그룹의 구성원에 변화가 생길 때, 즉 새로운 컨슈머가 그룹에 참여하거나 기존 컨슈머가 그룹을 이탈(장애, 종료 등)할 때, 파티션의 소유권을 그룹 내의 살아있는 컨슈머들에게 공정하게 재분배하는 과정을 리밸런싱이라고 한다.9 카프카는 각 컨슈머로부터 주기적으로 하트비트(heartbeat)를 받아 상태를 확인하며, 일정 시간 동안 하트비트가 수신되지 않으면 해당 컨슈머가 다운된 것으로 간주하고 리밸런싱을 자동으로 트리거한다.9 리밸런싱이 완료되면, 새로운 컨슈머는 자신이 할당받은 파티션의 마지막으로 커밋된 오프셋부터 메시지를 읽기 시작하므로, 데이터 손실이나 중복 처리 없이 작업을 이어갈 수 있다.9
2.6 컨트롤러의 역할: 주키퍼(ZooKeeper)에서 KRaft로의 진화와 그 의미
과거 카프카 클러스터는 분산 코디네이션 시스템인 아파치 주키퍼(Apache ZooKeeper)에 크게 의존했다. 주키퍼는 클러스터의 메타데이터(브로커 목록, 토픽 구성 정보, 접근 제어 목록 등)를 저장하고, 브로커의 상태 변화를 감지하며, 컨트롤러 브로커 선출 및 파티션 리더 선출과 같은 중요한 조정 작업을 담당했다.8
그러나 주키퍼는 카프카와는 별개의 분산 시스템으로, 이를 설치, 운영, 모니터링, 보안 설정하는 것은 상당한 운영 부담을 야기했다. 주키퍼 앙상블의 장애나 성능 저하는 카프카 클러스터 전체의 안정성에 직접적인 영향을 미치는 치명적인 외부 의존성이었다.
이러한 문제를 해결하기 위해 카프카 2.8.0 버전부터 KRaft(Kafka Raft) 프로토콜이 도입되기 시작했다.16 KRaft는 주키퍼를 완전히 제거하고, 카프카 브로커들 중 일부가 ‘컨트롤러’ 역할을 맡아 Raft 합의 알고리즘을 사용해 클러스터 메타데이터를 자체적으로 관리하는 방식이다.11
KRaft로의 전환이 갖는 의미는 매우 크다.
- 운영 단순화: 별도의 주키퍼 클러스터를 관리할 필요가 없어지므로 배포 토폴로지가 단순해지고, 관리해야 할 구성 요소가 줄어들어 운영 복잡성이 획기적으로 감소한다.
- 확장성 향상: 메타데이터 관리가 카프카 프로토콜 내부에서 더 효율적으로 처리되면서, 클러스터가 지원할 수 있는 파티션의 수가 크게 증가했다. KRaft 모드에서는 단일 클러스터에서 최대 2백만 개의 파티션을 지원할 수 있게 되어, 이전에는 불가능했던 초거대 규모의 클러스터 구축이 가능해졌다.11
- 성능 및 안정성 개선: 클러스터 시작 시간이 단축되고, 컨트롤러 장애 조치(failover)가 더 빨라지는 등 전반적인 시스템의 안정성과 성능이 향상된다. 외부 시스템에 대한 RPC 호출이 사라지고 모든 것이 카프카 내부에서 처리되기 때문이다.
결론적으로, KRaft로의 진화는 단순히 하나의 기능을 개선한 것이 아니라, 카프카를 더욱 견고하고 운영하기 쉬운 독립적인 시스템으로 만든 전략적인 변화이다. 이는 대규모 카프카 클러스터를 운영하는 데 있어 진입 장벽을 낮추고, 시스템의 전반적인 회복탄력성을 한 단계 끌어올리는 중요한 발전이라 할 수 있다.
3. 고성능의 원리: 처리량, 확장성, 그리고 내구성
아파치 카프카가 현대 데이터 아키텍처의 핵심으로 자리 잡을 수 있었던 가장 큰 이유는 타의 추종을 불허하는 성능에 있다. 본 장에서는 카프카가 어떻게 초당 수백만 개의 메시지를 처리하는 압도적인 처리량, 페타바이트 규모의 데이터를 다룰 수 있는 수평적 확장성, 그리고 데이터 유실을 허용하지 않는 강력한 내구성을 동시에 달성하는지 그 기술적 원리를 심층적으로 분석한다.
3.1 압도적인 처리량의 비밀: Zero-Copy와 순차 I/O 최적화
카프카는 하드웨어의 성능을 극한까지 활용하기 위해 운영체제와 디스크 I/O 수준에서부터 치밀하게 설계되었다. 그 핵심에는 순차 I/O와 Zero-Copy라는 두 가지 기술이 있다.17
-
순차 I/O (Sequential I/O): 하드 디스크 드라이브(HDD)나 솔리드 스테이트 드라이브(SSD)와 같은 저장 장치는 임의의 위치에 데이터를 읽고 쓰는 랜덤 접근(Random Access)보다, 데이터를 처음부터 끝까지 순서대로 읽고 쓰는 순차 접근(Sequential Access)에서 훨씬 더 높은 성능을 발휘한다. 카프카의 커밋 로그 아키텍처는 모든 쓰기 작업이 항상 로그 파일의 끝에 데이터를 추가하는(append) 형태로 이루어지도록 설계되었다.7 이는 디스크 헤드의 움직임을 최소화하고 운영체제의 페이지 캐시(Page Cache)를 효율적으로 활용하게 하여, 디스크 I/O로 인한 병목 현상을 극적으로 줄인다. 이 덕분에 카프카는 디스크 기반 스토리지 시스템임에도 불구하고 인메모리(in-memory) 메시지 큐에 필적하는 쓰기 성능을 보여준다.
-
Zero-Copy: 전통적인 애플리케이션이 디스크의 파일을 네트워크를 통해 전송할 때, 데이터는 여러 단계의 복사 과정을 거친다. 예를 들어, (1) 디스크에서 커널 버퍼로, (2) 커널 버퍼에서 애플리케이션 버퍼로, (3) 애플리케이션 버퍼에서 소켓 버퍼로, (4) 소켓 버퍼에서 네트워크 카드로 데이터가 복사된다. 이 과정에서 CPU는 여러 번의 컨텍스트 스위칭(Context Switching)과 데이터 복사 연산을 수행해야 하므로 상당한 오버헤드가 발생한다.17
카프카는 이 비효율을 제거하기 위해 운영체제가 제공하는 Zero-Copy 기술을 적극적으로 활용한다.17 컨슈머가 데이터를 요청할 때, 카프카 브로커는 Java NIO의
transferTo() 메소드를 호출하는데, 이는 내부적으로 sendfile 시스템 콜을 사용한다. sendfile은 커널에게 디스크(정확히는 커널의 페이지 캐시)에 있는 데이터를 사용자 공간(애플리케이션 메모리)으로 복사하는 과정 없이, 커널 공간에서 직접 네트워크 소켓 버퍼로 전송하라고 지시한다.17 이로써 데이터 복사 횟수와 컨텍스트 스위칭 횟수가 절반으로 줄어들고, CPU 사용률이 크게 감소하며, 동일한 하드웨어 자원으로 훨씬 더 많은 데이터를 네트워크로 전송할 수 있게 된다. Zero-Copy는 카프카가 대용량 데이터를 낮은 지연 시간으로 스트리밍할 수 있게 하는 가장 핵심적인 성능 최적화 기법 중 하나이다.4
3.2 수평적 확장성: 파티션을 통한 병렬 처리 극대화
카프카의 확장성은 ’파티션(Partition)’이라는 개념에 완벽하게 기반하고 있다.4 단일 브로커의 처리 능력에는 명백한 한계가 존재한다. 카프카는 이 한계를 극복하기 위해 토픽의 데이터를 여러 개의 파티션으로 분할하고, 이 파티션들을 클러스터 내의 여러 브로커에 분산시키는 전략을 사용한다.9
이러한 파티셔닝은 두 가지 측면에서 확장성을 제공한다.
- 부하 분산 (Load Distribution): 프로듀서는 여러 파티션에 동시에 데이터를 쓸 수 있고, 컨슈머 그룹의 각 컨슈머는 서로 다른 파티션으로부터 병렬로 데이터를 읽을 수 있다.17 따라서 데이터 처리 부하가 클러스터 전체에 고르게 분산된다. 시스템에 부하가 증가하면, 단순히 브로커를 클러스터에 추가하고 토픽의 파티션 수를 늘리는 것만으로도 전체 처리 용량을 선형적으로 확장(scale out)할 수 있다.4
- 병렬 처리 (Parallelism): 파티션은 병렬성의 기본 단위다.5 토픽에 10개의 파티션이 있다면, 최대 10개의 컨슈머가 동시에 해당 토픽의 데이터를 처리할 수 있다. 이는 데이터 처리 속도를 극대화하는 핵심적인 요소다. 카프카 클러스터는 이론적으로 수천 개의 브로커로 확장될 수 있으며, 이를 통해 하루에 수조 개의 메시지와 페타바이트(PB) 규모의 데이터를 처리하는 것이 가능하다.4
3.3 데이터 보존과 내구성: 영구 저장소(Permanent Storage)로서의 카프카
대부분의 전통적인 메시징 시스템은 컨슈머가 메시지를 성공적으로 수신하고 확인(acknowledgment)하면 해당 메시지를 큐에서 즉시 삭제한다.2 하지만 카프카는 근본적으로 다른 접근 방식을 취한다. 카프카는 이벤트를 일시적인 전달 매체가 아닌, 영구적으로 보존해야 할 중요한 기록으로 취급한다.4
카프카는 수신된 모든 이벤트를 설정된 보존 정책(retention policy)에 따라 디스크에 안전하게 저장한다.3 보존 정책은 시간 기반(예: 7일) 또는 크기 기반(예: 1GB)으로 설정할 수 있으며, 이 기간 동안 데이터는 소비 여부와 관계없이 절대 삭제되지 않는다.10
이러한 강력한 내구성(Durability)과 영속성(Persistence)은 카프카에 여러 가지 중요한 가치를 부여한다.
- 장애 복구: 컨슈머 애플리케이션에 버그가 발생하거나 장애로 인해 다운되더라도, 데이터는 카프카에 안전하게 보관되어 있다. 애플리케이션이 복구된 후, 마지막으로 처리했던 지점(오프셋)부터 다시 데이터를 읽어와 작업을 재개할 수 있다.7
- 데이터 재처리 및 분석: 동일한 데이터 스트림을 여러 다른 목적을 가진 컨슈머들이 각기 다른 시점에, 각자의 속도로 소비할 수 있다. 예를 들어, 실시간 모니터링 시스템, 배치 분석 시스템, 머신러닝 모델 학습 시스템이 모두 동일한 ‘주문’ 토픽을 독립적으로 구독하여 활용할 수 있다.2
- 진실의 원천 (Source of Truth): 카프카는 조직의 모든 이벤트에 대한 불변의 기록 저장소 역할을 할 수 있다. 이는 데이터 파이프라인의 복잡성을 줄이고, 여러 시스템 간의 데이터 일관성을 유지하는 데 큰 도움이 된다.4
결론적으로, 카프카의 영구 저장소 기능은 단순한 메시지 전달을 넘어, 신뢰할 수 있는 데이터 백본(backbone)으로서의 역할을 수행하게 하는 핵심적인 특징이다.
3.4 파티셔닝 전략: 데이터 분배의 예술
프로듀서가 메시지를 어떤 파티션으로 보낼지, 그리고 컨슈머 그룹이 파티션들을 어떻게 나누어 가질지를 결정하는 전략은 시스템의 로드 밸런싱, 메시지 순서 보장, 리밸런싱 효율성에 직접적인 영향을 미친다. 따라서 애플리케이션의 요구사항에 맞는 적절한 전략을 선택하는 것이 매우 중요하다.
3.4.1 프로듀서 파티션 전략
프로듀서는 partitioner.class 설정을 통해 파티셔닝 전략을 지정할 수 있다.13
- Default Partitioner (기본 파티셔너): 이 전략은 메시지에 키(key)가 있는지 여부에 따라 다르게 동작한다.13
- 키가 있는 경우: 키의 해시(hash) 값을 계산하고, 이 값을 파티션 수로 나눈 나머지(modulo)를 사용하여 특정 파티션을 결정한다. 이 방식은 동일한 키를 가진 모든 메시지가 항상 동일한 파티션으로 전송되도록 보장하므로, 특정 키에 대한 메시지 처리 순서가 중요한 경우(예: 특정 사용자의 활동 로그)에 매우 유용하다.9
- 키가 없는 경우 (null key): 초기에는 라운드 로빈 방식으로 파티션에 분배했으나, 최신 버전에서는 Uniform Sticky Partitioner와 유사하게 동작한다. 즉, 특정 파티션에 메시지를 “고정(stick)“시켜 배치(batch)를 채운 뒤, 다음 배치에서는 다른 파티션을 선택하는 방식이다. 이는 네트워크 요청 수를 줄여 지연 시간을 개선하는 효과가 있다.13
- Round-Robin Partitioner (라운드 로빈 파티셔너): 메시지 키의 존재 여부와 상관없이, 모든 메시지를 사용 가능한 파티션에 순서대로 균등하게 분배한다.13 이 전략은 로드 밸런싱을 최우선으로 고려할 때 유용하다. 특정 키에서 데이터가 쏠리는(skew) 현상을 방지할 수 있지만, 동일한 키에 대한 메시지 순서는 보장할 수 없다는 단점이 있다.
- Uniform Sticky Partitioner (균일 스티키 파티셔너): 이 전략의 목표는 지연 시간 감소와 균등한 분배를 동시에 달성하는 것이다. 메시지를 가능한 한 하나의 배치로 묶어 특정 파티션으로 보낸다. 배치가 가득 차거나
linger.ms시간이 초과되면 해당 배치를 전송하고, 다음 배치를 위해 새로운 ‘스티키’ 파티션을 선택한다.13 이를 통해 프로듀서는 더 적은 수의 더 큰 배치를 보내게 되어 네트워크 오버헤드를 줄이고 처리량을 높일 수 있다.
3.4.2 컨슈머 파티션 할당 전략
컨슈머 그룹 내에서 파티션을 어떻게 분배할지는 partition.assignment.strategy 설정을 통해 결정된다.13
- Range Assignor (레인지 할당자, 기본값): 이 전략은 각 토픽별로 독립적으로 작동한다. 각 토픽의 파티션들을 번호 순으로 정렬하고, 컨슈머들을 이름의 사전 순으로 정렬한다. 그런 다음, 전체 파티션 수를 컨슈머 수로 나누어 각 컨슈머에게 할당될 파티션의 ’범위(range)’를 결정한다.13 예를 들어, 10개의 파티션을 3개의 컨슈머가 구독하면 C1에게는 P0-P3, C2에게는 P4-P6, C3에게는 P7-P9가 할당될 수 있다. 이 방식은 구현이 간단하지만, 파티션 수가 컨슈머 수로 나누어 떨어지지 않을 경우 특정 컨슈머에게 더 많은 파티션이 할당되어 불균등한 분배가 발생할 수 있다.
- Round-Robin Assignor (라운드 로빈 할당자): 이 전략은 구독하는 모든 토픽의 모든 파티션을 하나의 리스트로 모은 뒤, 이 리스트를 컨슈머들에게 라운드 로빈 방식으로 하나씩 순서대로 할당한다.13 이는 Range 방식보다 더 균등한 파티션 분배를 보장하는 경향이 있다. 특히 여러 컨슈머가 여러 토픽을 구독하는 복잡한 시나리오에서 유용하다.
- Sticky Assignor (스티키 할당자): 이 전략은 리밸런싱 효율성을 극대화하는 데 초점을 맞춘다. 초기 할당은 라운드 로빈과 유사하게 최대한 균등하게 분배하는 것을 목표로 한다. 하지만 리밸런싱이 발생할 때(예: 컨슈머 하나가 다운될 때), 기존의 파티션-컨슈머 매핑을 최대한 유지하려고 시도한다.13 즉, 꼭 필요한 최소한의 파티션만 이동시킨다. 이는 리밸런싱으로 인해 발생하는 작업 중단 시간과 상태 저장 스트림 처리(stateful stream processing)에서의 상태 마이그레이션 비용을 최소화하는 데 매우 효과적이어서, 동적으로 컨슈머 수가 변하는 클라우드 환경 등에서 강력히 권장된다.
다음 표는 각 전략의 특징을 요약한 것이다.
표 1: 프로듀서 및 컨슈머 파티셔닝/할당 전략 비교
| 전략 이름 | 유형 | 핵심 특징 | 주요 사용 사례 | 장점 | 단점 |
|---|---|---|---|---|---|
| Default Partitioner | 프로듀서 | 키 해싱 기반 파티셔닝, 키가 없으면 스티키 방식 | 메시지 순서 보장이 필요한 경우 (예: 사용자별 이벤트 처리) | 특정 키에 대한 순서 보장 | 키가 편중될 경우 데이터 쏠림(hot partition) 발생 가능 |
| Round-Robin Partitioner | 프로듀서 | 모든 파티션에 균등하게 분배 | 로드 밸런싱이 최우선이고 순서가 중요하지 않은 경우 | 데이터 쏠림 방지, 균등한 부하 분산 | 키 기반 순서 보장 불가 |
| Uniform Sticky Partitioner | 프로듀서 | 배치 크기를 최대화하여 지연 시간 감소 | 높은 처리량과 낮은 지연 시간이 동시에 요구될 때 | 네트워크 효율성 향상, 처리량 증대 | 키 기반 순서 보장 불가 |
| Range Assignor | 컨슈머 | 토픽별로 파티션 범위를 계산하여 할당 (기본값) | 단순한 구독 시나리오 | 구현이 간단하고 직관적 | 컨슈머 간 불균등한 파티션 할당 가능성 |
| Round-Robin Assignor | 컨슈머 | 모든 파티션을 모아 라운드 로빈으로 할당 | 여러 토픽을 구독하는 복잡한 시나리오 | Range보다 균등한 분배 보장 | 리밸런싱 시 파티션 이동이 많을 수 있음 |
| Sticky Assignor | 컨슈머 | 리밸런싱 시 파티션 이동 최소화 | 동적 환경(오토스케일링), 상태 저장 스트림 처리 | 리밸런싱 오버헤드 최소화, 안정성 향상 | 할당 로직이 상대적으로 복잡함 |
4. 아파치 카프카 실전 활용 가이드
이론적 이해를 바탕으로, 본 장에서는 아파치 카프카를 실제로 설치하고 운영하며 애플리케이션과 연동하는 구체적인 방법을 다룬다. 로컬 환경 구축부터 CLI(Command-Line Interface)를 이용한 기본 조작, 그리고 Java와 Python을 사용한 프로그래밍 예제까지, 단계별 실습 가이드를 통해 카프카 활용 능력을 배양하는 것을 목표로 한다.
4.1 로컬 환경 구축
카프카를 로컬 머신에서 실행하는 방법은 크게 바이너리 파일을 직접 다운로드하는 방식과 Docker를 이용하는 방식으로 나뉜다.
4.1.1 사전 준비
어떤 방식을 사용하든, 카프카는 JVM(Java Virtual Machine) 위에서 실행되므로 Java 설치가 필수적이다. 공식 문서에 따르면 Java 17 또는 그 이상의 버전이 필요하다.1 터미널에서 java -version 명령어를 실행하여 설치된 Java 버전을 확인할 수 있다.12
4.1.2 바이너리 다운로드 및 설치 (Linux/macOS/Windows)
-
카프카 다운로드: 아파치 카프카 공식 웹사이트의 다운로드 페이지에서 최신 안정화 버전의 바이너리 릴리스(
tgz파일)를 다운로드한다.1 Scala 버전에 따라 여러 옵션이 제공되지만, 특별한 이유가 없다면 권장되는 Scala 버전(예: 2.13)을 선택하면 된다. -
압축 해제: 다운로드한 파일을 원하는 디렉터리에 압축 해제한다.1
Bash
$ tar -xzf kafka_2.13-4.0.0.tgz
$ cd kafka_2.13-4.0.0
Windows 환경에서는 WSL2(Windows Subsystem for Linux 2)를 설치하여 Linux 환경에서 진행하거나, Windows용 압축 해제 도구를 사용하고 bin\windows 디렉터리의 배치 스크립트를 사용해야 한다.19
4.1.3 Docker 기반 설치
Docker를 사용하면 Java나 기타 의존성 설치 과정 없이 격리된 환경에서 카프카를 손쉽게 실행할 수 있어 개발 및 테스트 환경에 매우 유용하다.
- Docker 이미지 가져오기: Apache Kafka 공식 Docker 이미지를 Docker Hub에서 가져온다.1
Bash
$ docker pull apache/kafka:4.0.0
- Docker 컨테이너 실행: 다운로드한 이미지를 사용하여 카프카 컨테이너를 실행한다.
-p옵션으로 호스트의 포트와 컨테이너의 포트를 매핑한다. 카프카는 기본적으로 9092 포트를 사용한다.
Bash
$ docker run -p 9092:9092 apache/kafka:4.0.0
이 명령어 하나로 독립 실행형(standalone) 카프카 서버가 실행 준비 상태가 된다.
4.1.4 서버 시작 (바이너리 설치 기준)
KRaft 모드가 기본이 된 최신 카프카 버전에서는 주키퍼 없이 단독으로 서버를 시작할 수 있다.
- 클러스터 UUID 생성: 클러스터를 식별할 고유 ID를 생성한다. 이 ID는 로그 디렉토리를 포맷할 때 사용된다.1
Bash
$ KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"
- 로그 디렉토리 포맷: 카프카가 데이터를 저장할 로그 디렉토리를 초기화한다. 이 과정에서 앞서 생성한 클러스터 ID와 서버 설정 파일(
config/server.properties) 경로를 지정한다.1
Bash
$ bin/kafka-storage.sh format -t $KAFKA_CLUSTER_ID -c config/server.properties
- 카프카 서버 시작: 서버 시작 스크립트를 실행하여 카프카 브로커를 구동한다.1
Bash
$ bin/kafka-server-start.sh config/server.properties
서버가 성공적으로 시작되면, 로컬 환경에 기본적인 카프카 환경이 구축되고 사용할 준비가 완료된다.
4.2 CLI를 이용한 기본 운영
카프카는 클러스터 관리, 테스트, 디버깅을 위한 강력한 CLI 도구들을 bin/ 디렉토리 하에 제공한다.15 이 도구들을 익히는 것은 카프카 운영에 필수적이다.15
4.2.1 토픽 관리 (kafka-topics.sh)
- 토픽 생성: 이벤트를 저장할 토픽을 생성한다. 새로운 터미널을 열고 다음 명령어를 실행한다.
--bootstrap-server는 연결할 카프카 브로커의 주소를 지정한다.1
Bash
$ bin/kafka-topics.sh --create --topic quickstart-events --bootstrap-server localhost:9092
- 토픽 목록 확인: 현재 클러스터에 생성된 모든 토픽의 목록을 확인한다.15
Bash
$ bin/kafka-topics.sh --list --bootstrap-server localhost:9092
- 토픽 상세 정보 확인: 특정 토픽의 파티션 수, 복제 계수(Replication Factor) 등 상세 설정을 확인한다.1
Bash
$ bin/kafka-topics.sh --describe --topic quickstart-events --bootstrap-server localhost:9092
- 토픽 삭제: 더 이상 사용하지 않는 토픽을 삭제한다.15
Bash
$ bin/kafka-topics.sh --delete --topic quickstart-events --bootstrap-server localhost:9092
4.2.2 메시지 발행 (kafka-console-producer.sh)
콘솔 프로듀서는 터미널에서 직접 메시지를 입력하여 지정된 토픽으로 전송하는 간단한 클라이언트다.15
Bash
$ bin/kafka-console-producer.sh --topic quickstart-events --bootstrap-server localhost:9092
> This is my first event
> This is my second event
프롬프트가 나타나면 한 줄에 하나씩 메시지를 입력하고 Enter 키를 누른다. 각 줄은 별개의 이벤트로 토픽에 저장된다. Ctrl-C를 눌러 프로듀서를 종료할 수 있다.18
4.2.3 메시지 구독 (kafka-console-consumer.sh)
콘솔 컨슈머는 지정된 토픽의 메시지를 실시간으로 읽어와 터미널에 출력한다.15
Bash
$ bin/kafka-console-consumer.sh --topic quickstart-events --from-beginning --bootstrap-server localhost:9092
This is my first event
This is my second event
--from-beginning 옵션은 토픽에 저장된 모든 메시지를 처음부터 읽어오도록 지시한다. 이 옵션을 생략하면 컨슈머가 시작된 이후에 발행된 새로운 메시지만 수신한다.15
Ctrl-C로 컨슈머를 종료할 수 있다.18
4.3 Java 클라이언트 프로그래밍
Java는 카프카의 네이티브 언어이며, 가장 성숙하고 기능이 풍부한 클라이언트 라이브러리를 제공한다.
4.3.1 기본 Java API
kafka-clients 라이브러리를 사용하여 KafkaProducer와 KafkaConsumer 객체를 직접 생성하고 설정하는 방식이다.
- 프로듀서 예제:
Java
// 1. Producer Properties 설정
Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
// 2. KafkaProducer 인스턴스 생성
try (Producer<String, String> producer = new KafkaProducer<>(props)) {
// 3. ProducerRecord 생성 및 전송
for (int i = 0; i < 100; i++) {
ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", Integer.toString(i), "my-message-" + i);
producer.send(record); // 비동기 전송
}
producer.flush(); // 모든 메시지가 전송되도록 보장
}
핵심은 ProducerConfig를 통해 브로커 주소와 메시지의 키/값을 바이트 배열로 변환할 직렬화기(Serializer)를 지정하는 것이다.10
- 컨슈머 예제:
Java
// 1. Consumer Properties 설정
Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "my-group"); // 컨슈머 그룹 ID 지정
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
props.put(Consumer.AUTO_OFFSET_RESET_CONFIG, "earliest");
// 2. KafkaConsumer 인스턴스 생성
try (final Consumer<String, String> consumer = new KafkaConsumer<>(props)) {
// 3. 토픽 구독
consumer.subscribe(Arrays.asList("my-topic"));
// 4. 메시지 폴링 및 처리
while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord<String, String> record : records) {
System.out.printf("Consumed record with key %s and value %s from partition %d at offset %d%n",
record.key(), record.value(), record.partition(), record.offset());
}
}
}
컨슈머는 ConsumerConfig에서 브로커 주소, 컨슈머 그룹 ID, 그리고 바이트 배열을 객체로 변환할 역직렬화기(Deserializer)를 설정해야 한다.10
consumer.poll() 메소드를 주기적으로 호출하여 브로커로부터 메시지를 가져온다.
4.3.2 Spring for Apache Kafka
Spring Boot 환경에서는 spring-kafka 라이브러리를 통해 훨씬 간결하고 선언적인 방식으로 카프카 클라이언트를 구현할 수 있다.21
- 프로듀서 (KafkaTemplate):
KafkaTemplate은 프로듀서 로직을 추상화하여 메시지 전송을 단순화한다.21
Java
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
public void sendMessage(String message) {
kafkaTemplate.send("my-topic", message);
}
- 컨슈머 (@KafkaListener):
@KafkaListener어노테이션을 메소드에 붙이는 것만으로 메시지를 수신하는 리스너를 손쉽게 만들 수 있다. 복잡한 폴링 루프나 스레드 관리가 필요 없다.21
Java
@KafkaListener(topics = "my-topic", groupId = "my-group")
public void listenGroupFoo(String message) {
System.out.println("Received Message in group my-group: " + message);
}
Spring for Kafka는 설정, 에러 핸들링, 트랜잭션 등 많은 부분을 자동화하고 추상화하여 개발자가 비즈니스 로직에만 집중할 수 있도록 돕는다.21
4.4 Python 클라이언트 프로그래밍
Python 생태계에서는 confluent-kafka-python 라이브러리가 사실상의 표준으로 사용된다. 이 라이브러리는 C로 작성된 고성능 librdkafka를 기반으로 하여 안정성과 속도를 모두 제공한다.24
- 설치:
Bash
pip install confluent-kafka
- 프로듀서 예제:
Python
from confluent_kafka import Producer
conf = {'bootstrap.servers': 'localhost:9092'}
producer = Producer(conf)
def delivery_report(err, msg):
if err is not None:
print(f'Message delivery failed: {err}')
else:
print(f'Message delivered to {msg.topic()} [{msg.partition()}]')
for i in range(10):
producer.produce('my-topic', key=str(i), value=f'message {i}', callback=delivery_report)
producer.flush() # 모든 메시지 전송 대기
- 컨슈머 예제:
Python
from confluent_kafka import Consumer
conf = {'bootstrap.servers': 'localhost:9092',
'group.id': 'my-group',
'auto.offset.reset': 'earliest'}
consumer = Consumer(conf)
consumer.subscribe(['my-topic'])
try:
while True:
msg = consumer.poll(1.0) # 1초 타임아웃
if msg is None:
continue
if msg.error():
print(f"Consumer error: {msg.error()}")
continue
print(f'Received message: {msg.value().decode("utf-8")}')
finally:
consumer.close()
Python 클라이언트 역시 Java와 마찬가지로 프로듀서와 컨슈머에 필요한 구성(configuration)을 딕셔너리 형태로 전달하여 인스턴스를 생성하고 사용한다.24
4.5 핵심 API 생태계 소개
카프카의 강력함은 프로듀서와 컨슈머 API를 넘어, 데이터 통합과 스트림 처리를 위한 확장 API 생태계에서 더욱 빛을 발한다.
- Kafka Connect: 카프카와 외부 시스템(예: 관계형 데이터베이스, NoSQL, Elasticsearch, HDFS, S3) 간의 데이터를 안정적이고 확장 가능한 방식으로 스트리밍하기 위한 프레임워크다.5 개발자는 코드를 작성하는 대신, JSON 설정 파일만으로 **소스 커넥터(Source Connector)**를 통해 외부 시스템의 데이터를 카프카로 가져오거나, **싱크 커넥터(Sink Connector)**를 통해 카프카의 데이터를 외부 시스템으로 내보낼 수 있다.5 Kafka Connect는 데이터 파이프라인 구축에 필요한 보일러플레이트 코드를 제거하여 개발 생산성을 크게 향상시킨다.26
- Kafka Streams: 카프카 토픽에 저장된 데이터를 실시간으로 처리하고 변환하는 애플리케이션을 구축하기 위한 경량 클라이언트 라이브러리다.5 별도의 스트림 처리 클러스터(예: Apache Spark, Apache Flink)를 구축할 필요 없이, Java 애플리케이션 내에서 직접 상태 저장(stateful) 또는 비상태 저장(stateless) 스트림 처리 로직(필터링, 조인, 집계, 윈도잉 등)을 구현할 수 있다.4 이는 카프카 생태계 내에서 완전한 실시간 데이터 처리 파이프라인을 구축할 수 있게 해주는 강력한 도구다.
5. 주요 사용 사례 및 실제 적용
아파치 카프카는 단순한 기술을 넘어, 현대적인 데이터 중심 아키텍처를 구현하는 핵심적인 플랫폼으로 자리매김했다. 본 장에서는 카프카가 실제로 어떤 문제들을 해결하는 데 사용되는지 주요 사용 사례를 분석하고, 글로벌 기업들이 카프카를 어떻게 활용하여 비즈니스 가치를 창출하는지 구체적인 전략을 살펴본다. 또한, 이벤트 기반 아키텍처(EDA)의 구현 원리로서 카프카의 역할을 조명한다.
5.1 현대적 아키텍처의 중추: 주요 사용 사례 분석
카프카는 그 유연성과 성능 덕분에 다양한 시나리오에 적용될 수 있다.
- 메시징 (Messaging): 카프카는 ActiveMQ나 RabbitMQ와 같은 전통적인 메시지 브로커를 대체하는 강력한 솔루션으로 사용된다.27 기존 메시지 브로커 대비 더 높은 처리량, 내장된 파티셔닝을 통한 확장성, 복제를 통한 내결함성, 그리고 강력한 내구성 보장을 제공하여 대규모 메시지 처리 시스템에 특히 적합하다.6 시스템 간의 처리를 분리(decouple)하고 비동기 통신을 구현하는 데 효과적이다.
- 로그 수집 (Log Aggregation): 분산 환경의 수많은 서버와 애플리케이션에서 생성되는 로그 파일들을 중앙화된 카프카 토픽으로 수집하는 용도로 널리 사용된다.6 기존의 로그 수집 솔루션(예: Flume)과 비교하여, 카프카는 파일의 세부 사항을 추상화하고 로그를 이벤트 스트림으로 다루게 함으로써 더 낮은 지연 시간과 높은 내구성을 제공한다.27 수집된 로그 데이터는 Kafka Connect를 통해 Elasticsearch, Splunk, OpenSearch와 같은 분석 시스템으로 실시간 전송되어 대시보드 모니터링, 이상 징후 탐지, 보안 분석, 트러블슈팅에 활용될 수 있다.28
- 웹사이트 활동 추적 (Website Activity Tracking): 카프카가 링크드인에서 처음 개발된 계기가 된 원조 사용 사례다.27 사용자의 페이지뷰, 클릭, 검색, 장바구니 담기 등 웹사이트 내 모든 상호작용을 실시간 이벤트로 생성하여 카프카 토픽에 발행한다.3 이 데이터 스트림은 실시간 대시보드 업데이트, 개인화된 상품 추천, 사기 탐지, 사용자 행동 분석 등 다양한 다운스트림 애플리케이션에서 즉시 구독하여 활용할 수 있다.6
- 이벤트 소싱 (Event Sourcing): 애플리케이션의 현재 상태를 직접 저장하는 대신, 상태를 변화시키는 모든 ’이벤트’를 시간 순서대로 로그에 기록하는 아키텍처 패턴이다.27 카프카의 불변하고 순서가 보장되는 대용량 로그 저장 능력은 이벤트 소싱 패턴을 위한 완벽한 이벤트 저장소(Event Store) 역할을 한다.27 특정 시점의 상태를 재구성해야 할 경우, 처음부터 해당 시점까지의 이벤트를 다시 재생(replay)하기만 하면 된다. 이는 시스템의 감사 추적(audit trail)과 디버깅을 용이하게 만든다.
- 스트림 처리 (Stream Processing): 카프카는 데이터가 발생하는 즉시 처리하는 실시간 스트림 처리의 핵심 허브 역할을 한다. 원시 데이터(raw data)가 카프카 토픽으로 들어오면, Kafka Streams나 Apache Flink, Apache Spark Streaming과 같은 처리 엔진이 이를 구독하여 필터링, 보강(enrichment), 집계(aggregation), 변환(transformation) 등의 처리를 수행하고, 그 결과를 다시 새로운 카프카 토픽으로 발행한다.27 이러한 다단계 처리 파이프라인을 통해 실시간으로 정제된 데이터 흐름 그래프를 생성할 수 있다.
5.2 글로벌 기업들의 카프카 활용 전략
수많은 글로벌 테크 기업들이 카프카를 자사 서비스의 핵심 인프라로 채택하여 비즈니스 혁신을 이루고 있다.
- Netflix: 세계 최대의 스트리밍 서비스인 넷플릭스는 사용자 경험을 최적화하기 위해 카프카를 광범위하게 사용한다. 사용자가 콘텐츠를 재생, 일시정지, 탐색하는 모든 행동은 이벤트로 생성되어 카프카로 전송된다. 이 실시간 이벤트 스트림을 분석하여 사용자의 네트워크 상태 변화를 감지하고, 버퍼링을 최소화하기 위해 비디오 스트리밍 품질을 동적으로 조절한다.29 또한, 시청 기록, 선호도 등의 데이터를 처리하여 고도로 개인화된 콘텐츠 추천 시스템을 구동하는 데에도 카프카가 핵심적인 역할을 한다.
- Uber/Lyft: 차량 공유 서비스의 대명사인 우버는 실시간 데이터 처리가 비즈니스의 성패를 좌우한다. 수백만 명의 운전자 위치 정보, 승객의 실시간 호출 요청, 도로 교통 상황 데이터 등 방대한 양의 이벤트가 끊임없이 카프카로 스트리밍된다.29 우버는 이 데이터를 집계하고 분석하여 운전자와 승객을 최적으로 매칭하고, 수요와 공급에 따라 가격을 실시간으로 조절하는 동적 가격 책정(surge pricing)을 구현하며, 정확한 도착 예정 시간(ETA)을 계산하는 데 활용한다.4
- LinkedIn: 카프카를 탄생시킨 링크드인은 자사 플랫폼의 거의 모든 데이터 파이프라인의 근간으로 카프카를 사용한다.29 사용자의 프로필 업데이트, 연결 요청, 게시물 작성과 같은 활동 데이터와 소셜 그래프 정보를 처리하여 실시간으로 뉴스피드를 업데이트하고, 구직자에게 맞춤형 일자리를 추천하는 시스템을 운영한다. 카프카는 이 모든 데이터 흐름을 안정적으로 관리하는 중추 역할을 한다.4
- Tesla: 테슬라는 전 세계에 운행 중인 수십만 대의 차량으로부터 방대한 양의 텔레메트리 데이터(주행 데이터, 센서 값, 부품 상태 등)를 실시간으로 수집하는 데 카프카를 활용한다.29 이 데이터는 중앙 서버로 스트리밍되어 차량의 문제를 원격으로 진단하고, 고장 가능성을 예측하여 사전 정비를 알리며(predictive maintenance), 자율 주행 알고리즘을 개선하기 위한 머신러닝 모델 학습에 사용된다. 이를 통해 차량의 안정성과 고객 경험을 지속적으로 향상시킨다.26
5.3 이벤트 기반 아키텍처(EDA)와 시스템 디커플링(Decoupling)의 구현
카프카의 가장 중요한 아키텍처적 가치 중 하나는 시스템 간의 강력한 **디커플링(Decoupling)**을 가능하게 한다는 점이다.1 전통적인 동기식(synchronous) 마이크로서비스 아키텍처에서는 서비스 A가 서비스 B를, 서비스 B가 서비스 C를 직접 호출하는 연쇄적인 구조를 갖기 쉽다. 이 경우, 서비스 C에 장애가 발생하면 그 여파가 서비스 B와 A로 전파되어 전체 시스템의 장애로 이어지는 ’연쇄 실패(cascading failure)’의 위험이 크다.
카프카는 이러한 문제를 해결하기 위해 **이벤트 기반 아키텍처(Event-Driven Architecture, EDA)**의 중심 허브 역할을 수행한다.7
- 결합 제거: 서비스 A는 더 이상 서비스 B를 직접 호출하지 않는다. 대신, ’주문이 생성됨(OrderPlaced)’과 같은 이벤트를 카프카 토픽에 발행하고 자신의 임무를 마친다.
- 독립적 소비: 서비스 B(예: 재고 관리 서비스)와 서비스 C(예: 알림 서비스)는 각각 ‘OrderPlaced’ 토픽을 독립적으로 구독한다. 이들은 서비스 A의 존재를 알 필요가 없으며, 이벤트가 발생했다는 사실에만 반응하여 각자의 로직을 수행한다.
- 회복탄력성 향상: 만약 재고 관리 서비스가 일시적으로 다운되더라도, ‘OrderPlaced’ 이벤트는 카프카에 안전하게 보관된다. 서비스가 복구되면, 저장되어 있던 이벤트를 가져와 처리를 재개할 수 있다. 즉, 한 서비스의 장애가 다른 서비스의 동작에 영향을 미치지 않아 시스템 전체의 회복탄력성(resilience)이 크게 향상된다.7
이처럼 프로듀서와 컨슈머가 서로를 전혀 인지하지 못하는 완전한 디커플링 구조는 카프카의 핵심 설계 원칙이다.1 카프카는 서비스 간의 비동기 통신을 강제하고, 일시적인 장애나 부하 급증을 흡수하는 내구성 있는 버퍼(durable buffer) 역할을 함으로써, 각 마이크로서비스가 독립적으로 개발, 배포, 확장될 수 있는 유연하고 견고한 시스템을 구축하는 것을 가능하게 한다. 이는 단순히 ‘빅데이터’ 파이프라인을 넘어, 현대적인 마이크로서비스 시스템을 구축하는 강력한 아키텍처 패턴으로서 카프카의 가치를 보여준다.
6. 카프카와 다른 시스템들과의 비교 분석
아파치 카프카의 특징과 장점을 더 명확하게 이해하기 위해서는, 유사한 목적을 가진 다른 시스템들과의 비교가 필수적이다. 본 장에서는 전통적인 메시지 브로커의 대표 주자인 RabbitMQ와, 클라우드 환경에서 널리 사용되는 관리형 서비스인 Google Cloud Pub/Sub 및 Amazon Kinesis와의 비교 분석을 통해 각 시스템의 아키텍처 철학, 장단점, 그리고 적합한 사용 시나리오를 심층적으로 탐구한다.
6.1 전통적 메시지 브로커와의 비교: Kafka vs. RabbitMQ
카프카와 RabbitMQ는 모두 비동기 메시징을 구현하는 데 사용되지만, 그 근본적인 설계 철학과 아키텍처는 매우 다르다.
- 아키텍처 철학: 가장 큰 차이는 “누가 똑똑한가“에 있다.
- RabbitMQ: “Smart Broker, Dumb Consumer” 모델을 따른다.30 브로커(RabbitMQ 서버)가 Exchange, Queue, Binding, Routing Key 등 복잡한 라우팅 규칙을 이해하고 메시지를 정확한 목적지로 전달하는 지능적인 역할을 수행한다. 컨슈머는 단순히 할당된 큐에서 메시지를 수신하는 비교적 수동적인 역할을 한다.16
- Kafka: “Dumb Broker, Smart Consumer” 모델을 따른다.30 브로커는 받은 메시지를 단순히 로그에 순서대로 기록하고 보관하는 역할에 충실하다. 어떤 데이터를 읽을지, 어디까지 읽었는지(오프셋)를 결정하고 관리하는 책임은 전적으로 ‘똑똑한’ 컨슈머에게 있다.
- 메시지 모델: 데이터 소비 방식에서도 차이가 있다.
- RabbitMQ: 브로커가 컨슈머에게 메시지를 밀어주는(push) 모델을 기반으로 한다. 브로커는 컨슈머의 처리 속도를 고려하여 메시지를 전송하며, 컨슈머가 과부하되지 않도록 프리페치(prefetch) 제한과 같은 메커니즘을 제공한다.30
- Kafka: 컨슈머가 브로커로부터 데이터를 당겨오는(pull) 모델을 사용한다.30 컨슈머는 자신의 처리 능력에 맞춰 능동적으로 데이터를 요청하므로, 데이터 폭주 상황에서도 안정적으로 동작할 수 있다.
- 데이터 보존: 메시지의 생명 주기에 대한 관점이 근본적으로 다르다.
- RabbitMQ: 메시지를 일시적인 데이터로 간주한다. 기본적으로 컨슈머가 메시지를 성공적으로 처리하고 확인 응답(acknowledgment, ACK)을 보내면 해당 메시지는 큐에서 즉시 삭제된다.2
- Kafka: 메시지를 영구적인 기록(record)으로 간주한다. 메시지는 소비 여부와 관계없이 설정된 보존 기간(retention period) 동안 로그에 계속 저장된다. 이를 통해 여러 컨슈머가 동일한 메시지를 반복해서 읽거나, 과거 데이터를 재처리하는 것이 가능하다.2
이러한 차이점들은 두 시스템이 서로 다른 문제 해결에 최적화되어 있음을 보여준다. RabbitMQ는 복잡한 라우팅 로직이 필요하고 개별 메시지의 전달 보장이 중요한 트랜잭션 처리나 작업 큐(task queue)에 강점을 보인다. 반면, 카프카는 대용량의 이벤트 스트림을 안정적으로 수집하여 여러 다운스트림 시스템(실시간 분석, 로그 저장, 스트림 처리 등)에 공급하는 데이터 백본(backbone) 및 스트리밍 플랫폼 역할에 탁월하다.
다음 표는 카프카와 RabbitMQ의 핵심적인 차이점을 요약한 것이다.
표 2: Kafka와 RabbitMQ의 핵심 차이점 비교 분석
| 특징 | Apache Kafka | RabbitMQ |
|---|---|---|
| 핵심 철학 | 분산 커밋 로그, 스트리밍 플랫폼 | 지능형 메시지 브로커, AMQP 구현체 |
| 아키텍처 모델 | Dumb Broker, Smart Consumer (Pull 모델) | Smart Broker, Dumb Consumer (Push 모델) |
| 메시지 보존 | 정책 기반 영구 보존 (시간/크기) | 승인(ACK) 기반 삭제 (일시적) |
| 처리량 | 매우 높음 (초당 수백만 메시지) | 높음 (초당 수만 메시지) |
| 메시지 라우팅 | 토픽과 파티션 기반의 단순한 라우팅 | Exchange, Queue, Binding을 통한 복잡하고 유연한 라우팅 |
| 주요 사용 사례 | 대용량 데이터 스트리밍, 로그 수집, 이벤트 소싱, 실시간 분석 파이프라인 | 작업 큐, 마이크로서비스 간 비동기 통신, 복잡한 라우팅이 필요한 시스템 |
| 데이터 타입 | 운영 데이터(Operational Data), 이벤트 스트림 | 트랜잭션 데이터(Transactional Data), 명령어 |
6.2 클라우드 관리형 서비스와의 비교: Self-Managed Kafka vs. Google Pub/Sub vs. Amazon Kinesis
클라우드 시대가 도래하면서, 인프라를 직접 구축하고 운영하는(Self-Managed) 방식과 클라우드 제공업체가 제공하는 완전 관리형 서비스(Fully-Managed Service)를 사용하는 방식 사이의 선택은 중요한 아키텍처 결정이 되었다.
-
핵심 트레이드오프: 통제(Control) vs. 편의성(Convenience)
-
Self-Managed Kafka: 온프레미스 데이터 센터나 클라우드 가상 머신(EC2, GKE 등)에 직접 카프카 클러스터를 설치하고 운영하는 방식이다. 이는 인프라 구성, 버전 관리, 성능 튜닝, 보안 설정 등 모든 측면에서 완전한 통제권을 제공한다.31 특정 비즈니스 요구사항에 맞춰 시스템을 최적화할 수 있고, 특정 클라우드 벤더에 종속되지 않는 유연성을 확보할 수 있다. 하지만 클러스터 구축, 모니터링, 장애 대응, 업그레이드 등에 높은 수준의
운영 비용과 전문성이 요구된다는 명백한 단점이 있다.31
- Google Cloud Pub/Sub & Amazon Kinesis: 클라우드 제공업체가 모든 인프라 관리를 대신해주는 완전 관리형 서비스다. 사용자는 서버 프로비저닝, 패치, 확장, 장애 복구 등에 대해 전혀 신경 쓸 필요 없이 API를 통해 서비스를 이용하기만 하면 된다. 이는 압도적인 운영 편의성을 제공하며, 사용한 만큼만 비용을 지불하는 종량제(pay-as-you-go) 모델과 트래픽에 따른 자동 확장(auto-scaling) 기능은 초기 도입 비용을 낮추고 민첩성을 높여준다.31 그러나 성능 튜닝의 폭이 제한적이고, 제공되는 기능이 카프카보다 단순하며, 특정 클라우드 생태계에 강하게
종속될 수 있다는 단점이 있다.31
- 아키텍처 모델의 차이: Kinesis는 샤드(Shard)라는 프로비저닝 단위를 기반으로 하는 스트리밍 모델을 사용하며, 사용자가 직접 샤드 수를 관리하며 확장해야 한다. 반면 Pub/Sub는 프로비저닝 개념이 없는 발행-구독 메시징 모델을 사용하여 완전한 서버리스(serverless) 경험을 제공한다.32
결국 어떤 방식을 선택할지는 조직의 기술 역량, 예산, 성능 요구사항, 그리고 멀티 클라우드 전략 등 다양한 요소를 종합적으로 고려하여 결정해야 한다. 초기 단계의 스타트업이나 카프카 운영 전문 인력이 없는 조직에게는 관리형 서비스가 매력적인 선택일 수 있다. 반면, 대규모 트래픽을 처리해야 하고 시스템에 대한 세밀한 제어가 필요하며 특정 벤더에 대한 종속을 피하고자 하는 조직에게는 Self-Managed Kafka가 더 적합한 선택이 될 수 있다.
다음 표는 Self-Managed Kafka와 주요 클라우드 메시징 서비스를 비교한 것이다.
표 3: Self-Managed Kafka와 주요 클라우드 메시징 서비스 비교
| 특징 | Self-Managed Apache Kafka | Google Cloud Pub/Sub | Amazon Kinesis Data Streams |
|---|---|---|---|
| 배포 모델 | 온프레미스, 모든 클라우드 (IaaS) | 완전 관리형 서비스 (PaaS/Serverless) | 완전 관리형 서비스 (PaaS) |
| 운영 관리 | 높음 (사용자가 직접 설치, 구성, 모니터링, 업그레이드) | 매우 낮음 (Google이 모든 인프라 관리) | 낮음 (AWS가 인프라 관리, 샤드 프로비저닝은 사용자 책임) |
| 확장성 모델 | 수동/자동 (브로커 및 파티션 추가) | 자동 (트래픽 기반 완전 자동 확장) | 수동/자동 (샤드 수 조절) |
| 성능/처리량 | 매우 높음 (최대 성능 튜닝 가능) | 높음 (자동 확장되나 튜닝은 제한적) | 높음 (샤드 수에 비례) |
| 데이터 보존 | 유연함 (시간/크기 기반, 영구 보존 가능) | 최대 7일 (승인 후 삭제, Seek 기능으로 재생 가능) | 최대 365일 (기본 24시간) |
| 비용 모델 | 인프라 및 운영 비용 (자본 지출/운영 지출) | 종량제 (데이터 볼륨, API 호출 등) | 종량제 (샤드 시간, 데이터 볼륨 등) |
| 생태계 통합 | 매우 넓음 (Kafka Connect, 오픈소스 커넥터 다수) | Google Cloud 서비스와 긴밀한 통합 | AWS 서비스와 긴밀한 통합 |
| 적합한 경우 | 최대 성능/통제권 필요, 멀티/하이브리드 클라우드 전략, 카프카 전문 인력 보유 | 운영 단순성 최우선, GCP 생태계 활용, 서버리스 아키텍처 | 실시간 데이터 스트리밍, AWS 생태계 활용, 샤드 기반 용량 계획 선호 |
7. 결론 및 향후 전망
7.1 아파치 카프카의 핵심 가치 요약
아파치 카프카는 지난 10여 년간 단순한 메시징 시스템을 넘어 현대 데이터 아키텍처의 핵심 구성 요소로 진화했다. 본 안내서에서 심층적으로 분석한 바와 같이, 카프카의 핵심 가치는 두 가지로 요약될 수 있다. 첫째, 시스템 간의 직접적인 의존성을 제거하는 강력한 **‘디커플링 계층(Decoupling Layer)’**으로서의 역할이다. 프로듀서와 컨슈머가 서로를 인지할 필요 없는 비동기 통신 모델을 제공함으로써, 카프카는 마이크로서비스 아키텍처의 유연성, 확장성, 그리고 회복탄력성을 극대화한다. 둘째, 조직 내에서 발생하는 모든 이벤트를 시간 순서대로 기록하고 영구적으로 보존하는 신뢰할 수 있는 ‘시스템의 기록부(System of Record)’ 역할이다. 이는 데이터의 재처리, 감사, 그리고 다양한 분석 애플리케이션의 기반이 되어 데이터의 활용 가치를 극대화한다. 이 두 가지 가치는 높은 처리량, 수평적 확장성, 그리고 강력한 내구성이라는 기술적 우위 위에서 구현된다.
7.2 이벤트 스트리밍의 미래
데이터가 21세기의 원유로 비유되듯, 실시간으로 흐르는 데이터의 가치는 기하급수적으로 증가하고 있다. 이러한 시대적 흐름 속에서 이벤트 스트리밍 플랫폼의 중요성은 더욱 커질 수밖에 없다. 카프카는 이미 수많은 글로벌 기업들의 성공 사례를 통해 그 가치를 입증했으며, 앞으로 다가올 기술 혁신의 중심에서 더욱 중요한 역할을 수행할 것으로 전망된다.
- 실시간 AI/ML: 머신러닝 모델이 배치 학습을 넘어 실시간으로 들어오는 데이터 스트림을 통해 지속적으로 학습하고 추론하는 온라인 러닝(Online Learning) 패러다임에서, 카프카는 모델에 데이터를 공급하는 핵심 파이프라인 역할을 할 것이다.
- 사물 인터넷(IoT): 수십억 개의 디바이스에서 쏟아져 나오는 센서 데이터를 안정적으로 수집하고 처리하여 실시간 모니터링, 예측 정비, 스마트 자동화를 구현하는 데 카프카는 필수적인 인프라가 될 것이다.
- 차세대 데이터 아키텍처: 데이터 메시(Data Mesh)와 같이 분산되고 탈중앙화된 데이터 소유권을 지향하는 새로운 아키텍처에서도, 카프카는 각 도메인의 데이터를 ’데이터 제품(Data Product)’으로서 스트리밍 형태로 제공하는 표준 인터페이스 역할을 수행할 잠재력을 가지고 있다.
7.3 카프카 생태계의 발전 방향
아파치 카프카 커뮤니티는 현재의 성공에 안주하지 않고, 플랫폼을 더욱 강력하고 접근하기 쉽게 만들기 위한 노력을 지속하고 있다. 향후 카프카 생태계는 다음과 같은 방향으로 발전할 것으로 예상된다.
- 운영 단순화: KRaft 프로토콜의 완전한 정착은 주키퍼라는 무거운 외부 의존성을 제거하여 카프카의 운영 복잡성을 획기적으로 낮출 것이다. 이는 더 많은 조직이 전문가의 도움 없이도 카프카를 도입하고 운영할 수 있게 하는 중요한 변곡점이 될 것이다.
- 비용 효율성 증대: Tiered Storage와 같은 기능은 자주 접근하지 않는 오래된 데이터를 Amazon S3와 같은 저렴한 객체 스토리지로 자동 이전하여, 대용량 데이터를 장기간 보존하는 데 드는 스토리지 비용을 크게 절감시켜 줄 것이다.
- 스트림 처리와의 융합: Kafka Streams의 지속적인 기능 강화와 더불어, Apache Flink와 같은 강력한 외부 스트림 처리 엔진과의 통합이 더욱 긴밀해질 것이다. 이를 통해 카프카는 데이터의 저장과 전달을 넘어, 데이터 처리까지 아우르는 명실상부한 통합 스트리밍 데이터 플랫폼으로 거듭날 것이다.
결론적으로, 아파치 카프카는 지난 10년간 데이터 처리의 지형을 바꾸어 놓았으며, 앞으로의 10년 역시 ’움직이는 데이터’의 시대를 선도하는 가장 중요한 기술 중 하나로 그 영향력을 더욱 확장해 나갈 것이 자명하다.
8. 참고 자료
- Apache Kafka documentation, accessed July 6, 2025, https://kafka.apache.org/documentation/
- What is Kafka? - Apache Kafka Explained - AWS, accessed July 6, 2025, https://aws.amazon.com/what-is/apache-kafka/
- Apache Kafka: the real-time data processing platform - DataScientest, accessed July 6, 2025, https://datascientest.com/en/apache-kafka-the-real-time-data-processing-platform
- What is Apache Kafka? | Confluent, accessed July 6, 2025, https://www.confluent.io/what-is-apache-kafka/
- Apache Kafka Architecture Deep Dive - Confluent Developer, accessed July 6, 2025, https://developer.confluent.io/courses/architecture/get-started/
- Apache Kafka Use Cases: When To Use It? When Not To? | Upsolver, accessed July 6, 2025, https://www.upsolver.com/blog/apache-kafka-use-cases-when-to-use-not
- Kafka - System Design in a Hurry - Hello Interview, accessed July 6, 2025, https://www.hellointerview.com/learn/system-design/deep-dives/kafka
- Comprehensive Guide to Apache Kafka Architecture - System Design School, accessed July 6, 2025, https://systemdesignschool.io/blog/kafka-architecture
- Apache Kafka: Topics, Partitions, Brokers - DEV Community, accessed July 6, 2025, https://dev.to/jhonifaber/understanding-apache-kafka-topics-partitions-brokers-2182
- Introduction to Apache Kafka | Baeldung, accessed July 6, 2025, https://www.baeldung.com/apache-kafka
- Intro to Kafka Partitions | Apache Kafka® 101 - Confluent Developer, accessed July 6, 2025, https://developer.confluent.io/courses/apache-kafka/partitions/
- Apache Kafka Quick Guide - Tutorialspoint, accessed July 6, 2025, https://www.tutorialspoint.com/apache_kafka/apache_kafka_quick_guide.htm
- Kafka Partition Strategies: Optimize Your Data Streaming - Redpanda, accessed July 6, 2025, https://www.redpanda.com/guides/kafka-tutorial-kafka-partition-strategy
- Setting Up Apache Kafka Locally: A Step-by-Step Guide - DEV …, accessed July 6, 2025, https://dev.to/pragativerma18/setting-up-apache-kafka-locally-a-step-by-step-guide-2p8
- Exploring Kafka CLI. Learn how to create topics, produce… | by …, accessed July 6, 2025, https://medium.com/itversity/exploring-kafka-cli-8b383163ffdd
- RabbitMQ vs Kafka - Difference Between Message Queue Systems …, accessed July 6, 2025, https://aws.amazon.com/compare/the-difference-between-rabbitmq-and-kafka/
- Why is Kafka throughput so high / AutoMQ/automq Wiki / GitHub, accessed July 6, 2025, https://github.com/AutoMQ/automq/wiki/Why-is-Kafka-throughput-so-high
- Apache Kafka Quickstart - The Apache Software Foundation, accessed July 6, 2025, https://kafka.apache.org/quickstart
- Apache Kafka for Beginners: A Comprehensive Guide - DataCamp, accessed July 6, 2025, https://www.datacamp.com/tutorial/apache-kafka-for-beginners-a-comprehensive-guide
- Learn Kafka Programming Lesson: Complete Kafka Producer with Java - Conduktor, accessed July 6, 2025, https://learn.conduktor.io/kafka/complete-kafka-producer-with-java/
- Intro to Apache Kafka with Spring | Baeldung, accessed July 6, 2025, https://www.baeldung.com/spring-kafka
- tutorials/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java at master / eugenp/tutorials - GitHub, accessed July 6, 2025, https://github.com/eugenp/tutorials/blob/master/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java
- tutorials/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java at master / eugenp/tutorials - GitHub, accessed July 6, 2025, https://github.com/eugenp/tutorials/blob/master/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java
- Kafka Python Client and Streaming Quickstart - Oracle Help Center, accessed July 6, 2025, https://docs.oracle.com/en-us/iaas/Content/Streaming/Tasks/streaming-kafka-python-client-quickstart.htm
- Kafka | Confluent Documentation, accessed July 6, 2025, https://docs.confluent.io/kafka/overview.html
- Kafka Benefits and Use Cases - Confluent, accessed July 6, 2025, https://www.confluent.io/learn/apache-kafka-benefits-and-use-cases/
- Apache Kafka Use Cases - The Apache Software Foundation, accessed July 6, 2025, https://kafka.apache.org/uses
- Using Apache Kafka for log aggregation - Redpanda, accessed July 6, 2025, https://www.redpanda.com/guides/kafka-use-cases-log-aggregation
- Unlocking the Power of Apache Kafka: Real-World Examples and …, accessed July 6, 2025, https://medium.com/@horan.dev/unlocking-the-power-of-apache-kafka-real-world-examples-and-use-cases-1429cc55634a
- RabbitMQ vs. Kafka - Redpanda, accessed July 6, 2025, https://www.redpanda.com/guides/kafka-tutorial-rabbitmq-vs-kafka
- Apache Kafka vs. Google Pub_Sub: Differences & Comparison …, accessed July 6, 2025, https://github.com/AutoMQ/automq/wiki/Apache-Kafka-vs.-Google-Pub_Sub:-Differences-&-Comparison
- Google Pub Sub vs. Kinesis - Qlik, accessed July 6, 2025, https://www.qlik.com/us/data-ingestion/google-pub-sub-vs-kinesis